const path = require("path");
const fs = require("fs");
require("./extend");
const cos = require("./cos");

const COS_DOMAIN = "x.shuqianji.com";

const rootPath = process.cwd();
const inCode = /ubuntu/.test(rootPath);
const inLocal = !inCode;

module.exports = {
  inLocal,
  checkSize(name, size, arr) {
    if (!(size >= arr[0] && size <= arr[1])) {
      const scope = arr.map((it) => it + "px").join(", ");
      throw new Error(`${name}: [${scope}]`);
    }
    return size * 1;
  },
  async getIcons(page) {
    return page.$$eval("head > link", (list) => {
      return list
        .map((el) => {
          return {
            rel: el.rel,
            href: el.href,
          };
        })
        .filter((it) => /icon/.test(it.rel))
        .map((it) => it.href);
    });
  },
  async getMeta(page) {
    const info = await page.$$eval("head > meta", (list) => {
      const obj = {};
      list.forEach((el) => {
        if (el.name && el.content) obj[el.name] = el.content;
      });
      return obj;
    });
    return info;
  },
  async checkWait(page, query) {
    const extra = {};
    const waitArr = [];
    if (query.wait_el) {
      waitArr = query.wait_el.split(",");
    }
    if (waitArr.length) {
      extra.waited = [];
      extra.wait_fail = [];
      for (const el of waitArr) {
        if (!el) continue;
        try {
          await page.waitForSelector(el, {
            timeout: query.wait_el_t || 1000,
          });
          extra.waited.push(el);
        } catch (error) {
          extra.wait_fail.push(el);
        }
      }
    }
    return extra;
  },
  async checkClick(page, query) {
    const extra = {};
    let clickArr = [];
    if (query.click_el) {
      clickArr = query.click_el.split(",");
    }
    if (query.host == "blog.csdn.net") {
      clickArr = ["#passportbox>img", ".open-app-weixin"];
    } else if (query.host == "juejin.cn") {
      clickArr.push(".cancel-btn");
    }
    if (clickArr.length) {
      extra.clicked = [];
      extra.click_fail = [];
      for (const el of clickArr) {
        if (!el) continue;
        try {
          await page.click(el);
          extra.clicked.push(el);
        } catch (error) {
          extra.click_fail.push(el);
        }
      }
    }
    return extra;
  },
  async checkPage(page, query) {
    // https://qa.1r1g.com/sf/ask/3496270991/
    const check0 = await this.checkWait(page, query);
    const check1 = await this.checkClick(page, query);
    return {
      ...check0,
      ...check1,
    };
  },

  async getLinks(page, query) {
    const links = await page.$$eval(query.eval_link || "a[href]", (list) => {
      return list
        .map((el) => {
          return {
            txt: (el.textContent || "").trim(),
            url: (el.href || "").replace(/#.+$/, ""),
          };
        })
        .filter((it) => {
          return /^http/.test(it.url);
        })
        .slice(0, 300);
    });
    return this.uniqueBy(links, "url")
      .filter((it) => {
        return it.url != query.url;
      })
      .slice(0, 100);
  },
  async getImgs(page, query) {
    let imgs = await page.$$eval(query.eval_img || "img[src]", (list) => {
      return list
        .map((el) => {
          return {
            src: el.src,
            alt: el.alt,
            w: el.offsetWidth,
            h: el.offsetHeight,
          };
        })
        .filter((it) => {
          return /^http/.test(it.src) && it.src.length < 1024 && it.w > 0;
        })
        .slice(0, 100);
    });
    const { img_min_w = 30 } = query;
    imgs = imgs.filter((it) => it.w > img_min_w); // $$eval方法体内无法引用外部变量
    return this.uniqueBy(imgs, "src");
  },
  async getTxts(page, query) {
    const txts = await page.$$eval(
      query.eval_txt || "h1,h2,h3,h4,h5,h6,p,li",
      (list) => {
        return list
          .map((el) => {
            const obj = {
              txt: (el.textContent || "").trim(),
              tag: el.tagName,
            };
            if (obj.tag == "P") delete obj.tag;
            return obj;
          })
          .filter((it) => {
            return it.txt && !(it.tag != "P" && it.txt.length == 1);
          })
          .slice(0, 100);
      }
    );
    return this.uniqueBy(txts, "txt");
  },
  async getExtra(page, query) {
    const extra = {};
    if (query.eval_author) {
      extra.author = await page.$$eval(query.eval_author, (el) => {
        return el ? el.textContent : "";
      });
    }
    if (query.eval_desc) {
      extra.desc = await page.$$eval(query.eval_desc, (el) => {
        return el ? el.textContent : "";
      });
    }
    const videos = await page.$$eval(
      query.eval_video || "video[src]",
      (list) => {
        return list
          .map((el) => {
            return {
              src: el.src,
              w: el.offsetWidth,
              h: el.offsetHeight,
            };
          })
          .slice(0, 100);
      }
    );
    if (videos.length) {
      extra.videos = this.uniqueBy(videos, "src");
    }
    if (query.eval_file) {
      const files = await page.$$eval(query.eval_file, (list) => {
        return list
          .map((el) => {
            return {
              src: el[query.file_src] || el.src,
              txt: el[query.file_txt] || el.textContent,
            };
          })
          .slice(0, 100);
      });
      extra.files = this.uniqueBy(files, "src");
    }
    return extra;
  },
  uniqueBy(list, key) {
    const arr = [];
    return list.filter((it) => {
      if (arr.includes(it[key])) return false;
      arr.push(it[key]);
      return true;
    });
  },
  async getShot(page, query) {
    const shot = {};
    const date = new Date();
    const dir = `shot/${date.format("yyMM")}/`;
    let pre = `${date.format("dd")}-${query.host}-${query.hash}`;
    let root = rootPath;

    let name = pre + ".png";
    let toPath = path.join(root, name);
    await page.screenshot({
      path: toPath,
      fullPage: !!query.shot_full,
      type: "png",
    });
    shot.img = await this.postShot(dir + name, toPath);

    name = pre + ".pdf";
    toPath = path.join(root, name);
    await page.pdf({ path: toPath, format: query.pdf_format || "A4" });
    shot.pdf = await this.postShot(dir + name, toPath);

    return shot;
  },
  async postShot(name, toPath) {
    const { size } = fs.statSync(toPath);
    if (size < 10 * 1024 * 1024) {
      await cos.put(name, toPath);
    } else {
      name = "";
    }
    fs.unlink(toPath, (err) => {
      if (err) console.log("unlink fail", err.message);
    });
    return {
      name,
      size,
    };
  },
  async getShotUrl(obj) {
    if (!obj || !obj.name) return null;
    return cos.signatureUrl(obj.name, {
      Domain: COS_DOMAIN,
    });
  },
  autoScroll(page) {
    return page.evaluate(() => {
      return new Promise((resolve) => {
        let totalH = 0;
        const moveH = document.documentElement.clientHeight;
        var timer = setInterval(() => {
          window.scrollBy(0, moveH);
          totalH += moveH;
          const maxH = document.body.scrollHeight;
          if (totalH >= maxH) {
            clearInterval(timer);
            window.scrollTo(0, 0);
            resolve({
              maxH,
            });
          }
        }, 150);
      });
    });
  },
};
